﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using FastColoredTextBoxNS;
using System.IO;

namespace PSPGenerator
{
    delegate void Function();
    public partial class frmMain : Form
    {
        PSPTemplate pspTmp = new PSPTemplate();
        private string GetFileDestination { get { return System.Configuration.ConfigurationManager.AppSettings["FilesDestination"].ToString(); } }
        private string LoadPSPLocation  { get { return System.Configuration.ConfigurationManager.AppSettings["LoadPSPLocation"].ToString().Trim();}}
        private string SQLPlusLocation { get { return System.Configuration.ConfigurationManager.AppSettings["SQLPlusLocation"].ToString().Trim(); } }
        private string UserNamePassword { get { return System.Configuration.ConfigurationManager.AppSettings["UserNamePassword"].ToString(); } }

        public frmMain()
        {
            InitializeComponent();
        }

       
        private void btnGenerate_Click(object sender, EventArgs e)
        {
            PSPDefinition info = new PSPDefinition();
            if (txtProcedureName.Text == "" || txtAbb.Text == "" )
            {
                MessageBox.Show("Please fill up all empty boxes");
                return;
            }
            if (cbListTableNames.Text == "")
            {
                MessageBox.Show("Please select a table in List Tab");
                return;
            }
            bool isOneCheckBoxSelected= false;

            if (cbCreateList.Checked || cbCreateForm.Checked || cbCreateInsertUpdate.Checked || cbCreateDelete.Checked || cbCreateJSON.Checked) isOneCheckBoxSelected = true;
            if (isOneCheckBoxSelected==false)
            {
                MessageBox.Show("Please check one(1) these items \"List,Create, Update, and Delete\".");
                return;
            }

            var btn = (Button)sender;
            btn.Text = "Generating...";
            btn.Enabled = false;

            var plList = info.ProcedureList = new ProcedureList();
            var plForm = info.ProcedureForm = new ProcedureForm();
          

            info.ProcedureName = txtProcedureName.Text;
            info.PrimaryKey = this.clListProcParams.CheckedItems[0].ToString();
            info.AbbreviateKey = txtAbb.Text;
            info.FormTitle = this.txtFormTitle.Text;

            plList.TableName = this.cbListTableNames.Text;                    
            plList.ParametersProcedure = this.clListProcParams;
            plList.ParametersTableDisplay = this.clListTableDisplay;
            plList.ParametersDisplay = this.lbDisplayFields;
            //plList.ParametersDHTMLXFilter = this.lbDHTMLXFilter;
            plList.DeleteColumn = cbDeleteColumn.Checked;

            plForm.TableName = this.cbIUDTableName.Text != "" ? this.cbIUDTableName.Text : this.cbListTableNames.Text;
            plForm.ParametersProcedureInsert = this.clbInsertParams;
            plForm.ParametersProcedureUpdate = this.clbUpdateParams;
            plForm.ParametersProcedureDelete = this.clbDeleteParams;
            plForm.IsMultipleIUD = cbUpdateMultiple.Checked;

            try
            {
                pspTmp.CreateOptions = new CreateOptions()
                {
                    List = cbCreateList.Checked,
                    Form = cbCreateForm.Checked,
                    InsertUpdate = cbCreateInsertUpdate.Checked,
                    Delete = cbCreateDelete.Checked,
                    JSON = cbCreateJSON.Checked,
                    ToFiles = cbCreateToFiles.Checked
                };
               pspTmp.Generate(info);

                cbResultFiles.Items.Clear();
               if (cbCreateList.Checked){
                   cbResultFiles.Items.Add(string.Format("{0}_list.psp", txtProcedureName.Text));
               }
               if (cbCreateJSON.Checked)
               {
                   cbResultFiles.Items.Add(string.Format("{0}_json.sql", txtProcedureName.Text));
               }
               if (cbCreateForm.Checked){
                   cbResultFiles.Items.Add(string.Format("{0}_form.psp", txtProcedureName.Text));
               }
               if (cbCreateInsertUpdate.Checked){
                   cbResultFiles.Items.Add(string.Format("{0}_update.psp", txtProcedureName.Text));
               }
               if (cbCreateDelete.Checked){
                   cbResultFiles.Items.Add(string.Format("{0}_delete.psp", txtProcedureName.Text));
               }
                cbResultFiles.SelectedIndex = 0;

               tb.Text= File.ReadAllText(this.GetFileDestination + cbResultFiles.Items[0]);

                if (cbCreateAutoCompile.Checked)
                {
                    txtCompileResult.Text = "Compiling...";
                    txtCompileResult.Select(0, 0);
                    tabControl1.SelectTab(3);
                }
                
                bwCompile.RunWorkerAsync();

            }
            catch (Exception ex)
            {
                btnGenerate.Text = "Generate";
                btnGenerate.Enabled = true;
                MessageBox.Show(ex.Message, "Info");
            }
        }
 
        private void frmMain_Load(object sender, EventArgs e)
        {
            pnlDisplayField.Visible = false;
            tssFileLocation.Text = this.GetFileDestination;
            cbSnippetCodeType.SelectedIndex = 0;


        }

        private void lbDisplayFields_DoubleClick(object sender, EventArgs e)
        {
            var value = ((ListBox)sender).Text;
            txtDisplayFieldName.Text = value;
            pnlDisplayField.Visible = true;
            txtDisplayFieldName.Focus();
        }

        private void btnDisplayOK_Click(object sender, EventArgs e)
        {         
            lbDisplayFields.Items[lbDisplayFields.SelectedIndex]  = txtDisplayFieldName.Text;
            pnlDisplayField.Visible = false;
        }

        private void btnDisplayCancel_Click(object sender, EventArgs e)
        {
            pnlDisplayField.Visible = false;
        }

        private void setCheck_Uncheck_ListBox(CheckBox chk, CheckedListBox clstBox)
        {
            for (int x = 0; x < clstBox.Items.Count; x++)
            {

                clstBox.SetItemChecked(x, chk.Checked);

            }

        }

     
        private void txtDisplayFieldName_KeyPress(object sender, KeyPressEventArgs e)
        {
       
            if (e.KeyChar == (char)Keys.Return)
            {
                btnDisplayOK_Click(sender, new EventArgs());
                lbDisplayFields.Focus();
                e.Handled = true;
            }
                    
        }

        private void txtProcedureName_TextChanged(object sender, EventArgs e)
        {
            var txt = (TextBox)sender;
            System.Globalization.TextInfo textInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
            txtFormTitle.Text = textInfo.ToTitleCase(txt.Text.Replace("_", " "));

            string title = "";
            string[] chars =  txtFormTitle.Text.Split(' ');
            foreach (string value in chars) {
                if (value!="") title += value.Substring(0,1).ToLower(); 
            }
            txtAbb.Text = title;
        }

     

        private void tssFileLocation_Click(object sender, EventArgs e)
        {
            try
            {
                System.Diagnostics.Process.Start(@tssFileLocation.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Info");
            }
        }

        private void tb_TextChangedDelayed(object sender, TextChangedEventArgs e)
        {
            var ext = Path.GetExtension(lblResultFilename.Text);
            var tb = (FastColoredTextBox)sender;

            if (ext == ".psp")
            {
                tb.SyntaxHighlighter.InitStyleSchema(Language.HTML);
                tb.SyntaxHighlighter.HTMLSyntaxHighlight(tb.Range);
                
                foreach (var r in tb.GetRanges(@"<\%.*?\%>", RegexOptions.Singleline))
                {
                    r.ClearStyle(StyleIndex.All);
                    tb.SyntaxHighlighter.InitStyleSchema(Language.PHP);
                    tb.SyntaxHighlighter.PHPSyntaxHighlight(r);
                }
            }
            else if (ext == ".sql")
            {            
                tb.SyntaxHighlighter.InitStyleSchema(Language.SQL);
                tb.SyntaxHighlighter.SQLSyntaxHighlight(tb.Range);
            }
        }

        private void txtProcedureName_KeyPress(object sender, KeyPressEventArgs e)
        {
            if(e.KeyChar == (char)8) {
                return;
            }
            char keyChar = e.KeyChar;

            var txt = (TextBox)sender;

            if (keyChar.ToString() == " ")
            {
                txt.AppendText("_");
                e.Handled = true;
            }
            else {
                    if(keyChar.ToString() == keyChar.ToString().ToUpper())
                {
                
                    txt.AppendText(keyChar.ToString().ToLower());
                    e.Handled = true;
                }
            }

        }

        private void chkListAllParamsProc_CheckedChanged(object sender, EventArgs e)
        {
            setCheck_Uncheck_ListBox((CheckBox)sender, clListProcParams);

        }

        private void chkListAllParamsTable_CheckedChanged(object sender, EventArgs e)
        {
            setCheck_Uncheck_ListBox((CheckBox)sender, clListTableDisplay);
        }

        private void btnListLoadTables_Click(object sender, EventArgs e)
        {
            LoadTables(this.btnListLoadTables, this.cbListTableNames);
        }

        private void cbListTableNames_SelectedIndexChanged(object sender, EventArgs e)
        {
            CheckedListBox[] clCheckBoxes = { 
                this.clListProcParams, 
                this.clListTableDisplay, 
                this.clbInsertParams, 
                this.clbUpdateParams,
                this.clbDeleteParams
            };
            pspTmp.LoadTableFields(this.cbListTableNames.SelectedItem.ToString(), clCheckBoxes);
            lbDisplayFields.Items.Clear();
            //lbDHTMLXFilter.Items.Clear();
            foreach (string value in this.clListProcParams.Items)
            {
                System.Globalization.TextInfo textInfo = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo;
                string displayValue = textInfo.ToTitleCase(value.Replace("_", " "));
                lbDisplayFields.Items.Add(displayValue);
               // lbDHTMLXFilter.Items.Add(value + "#text_filter");
            }

        }

        private void btnIUDTables_Click(object sender, EventArgs e)
        {

            LoadTables(this.btnIUDTables, this.cbIUDTableName);
        }

        private void LoadTables(Button btn,ComboBox cb) {

            var title = btn.Text;
            btn.Text = "loading...";
            btn.Enabled = false;
            try
            {
                DataTable dt = new DataTable();
                dt = pspTmp.LoadTables();
                cb.Items.Clear();
                foreach (DataRow row in dt.Rows)
                {
                    cb.Items.Add(row["table_name"].ToString().ToUpper());
                }
                cb.DroppedDown = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Info");
            }
            btn.Enabled = true;
            btn.Text = title;
        }

        private void chkListAllParamsInsert_CheckedChanged(object sender, EventArgs e)
        {
            setCheck_Uncheck_ListBox((CheckBox)sender, clbInsertParams);
        }

        private void chkListAllParamsUpdate_CheckedChanged(object sender, EventArgs e)
        {
            setCheck_Uncheck_ListBox((CheckBox)sender, clbUpdateParams);
        }

        private void chkListAllParamsDelete_CheckedChanged(object sender, EventArgs e)
        {
            setCheck_Uncheck_ListBox((CheckBox)sender, clbDeleteParams);
        }

        private void cbIUDTableName_SelectedIndexChanged(object sender, EventArgs e)
        {
            CheckedListBox[] clCheckBoxes = { this.clbInsertParams, this.clbUpdateParams, this.clbDeleteParams };
            pspTmp.LoadTableFields(cbIUDTableName.SelectedItem.ToString(), clCheckBoxes);
        }

        private void lbDisplayFields_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Return)
            {
                lbDisplayFields_DoubleClick(sender, new EventArgs());
            }
        }

        /*private void lbDHTMLXFilter_DoubleClick(object sender, EventArgs e)
        {
            var lb = ((ListBox)sender);
            var sharpIndex = lb.Text.IndexOf('#');
            var currentFilter=lb.Text.Substring(sharpIndex);
            switch (currentFilter) {
                case "#text_filter":
                   lb.Items[lb.SelectedIndex] = lb.Text.Substring(0, sharpIndex) + "#select_filter";
                    break;
                case "#select_filter":
                    lb.Items[lb.SelectedIndex] = lb.Text.Substring(0, sharpIndex) + "#combo_filter";
                    break;
                case "#combo_filter":
                    lb.Items[lb.SelectedIndex] = lb.Text.Substring(0, sharpIndex) + "#text_search";
                    break;
                case "#text_search":
                    lb.Items[lb.SelectedIndex] = lb.Text.Substring(0, sharpIndex) + "#numeric_filter";
                    break;
                case "#numeric_filter":
                    lb.Items[lb.SelectedIndex] = lb.Text.Substring(0, sharpIndex) + "#text_filter";
                    break;
                default: break;
            }
        
        }*/

        private string CompilePSP(string FileName) {
            string result ="";
            string ext = Path.GetExtension(FileName);
            if (ext == ".psp" || ext == ".sql")
            {
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.CreateNoWindow = true;

                if (ext == ".psp")
                {
                    p.StartInfo.FileName = this.LoadPSPLocation + "loadpsp.exe";
                    p.StartInfo.Arguments = string.Format("-replace -user {0} {1}", this.UserNamePassword, FileName);                
                }
                else
                {
                    p.StartInfo.FileName = this.SQLPlusLocation  + "sqlplus.exe";
                    p.StartInfo.Arguments = string.Format("-S {0} @{1}", this.UserNamePassword, FileName);
                }
                p.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(Compile_OutputDataReceived);
                p.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(Compile_ErrorDataReceived);
                p.Exited += new EventHandler(Compile_Exited);
                var pw = p.Start();

                if (ext == ".sql"){
                    p.StandardInput.WriteLine("exit");
                }
                p.BeginErrorReadLine();
                p.BeginOutputReadLine();

               // p.Close();                
                 
            }
            return result;
        }

        void Compile_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                this.Invoke(new Function(delegate()
                {

                    if (txtCompileResult.Text.Trim() != "") txtCompileResult.Text += "\r\n";
                    txtCompileResult.AppendText(e.Data);

                }));
            }
        }

        void Compile_ErrorDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (e.Data != null)
            {
                this.Invoke(new Function(delegate()
                {

                    if (txtCompileResult.Text.Trim() != "") txtCompileResult.Text += "\r\n";
                    txtCompileResult.AppendText(e.Data);
                        System.Media.SystemSounds.Exclamation.Play();                    

                }));
            }

        }

        void Compile_Exited(object sender, EventArgs e)
        {
            System.Media.SystemSounds.Beep.Play();
        }


        private void StartCompile() {
           
            if (cbCreateToFiles.Checked && cbCreateAutoCompile.Checked)
            {
                string result = "";

                string fileNameTmp = string.Format("{0}{1}_{2}.psp", this.GetFileDestination, txtProcedureName.Text, "{0}");

                if (cbCreateList.Checked)
                {
                    result += CompilePSP(string.Format(fileNameTmp,"list"));
                }
                if (cbCreateForm.Checked)
                {
                    if (result != "") result += "\r\n\r\n";
                    result += CompilePSP(string.Format(fileNameTmp, "form"));
                }
                if (cbCreateInsertUpdate.Checked)
                {
                    if (result != "") result += "\r\n\r\n";
                    result += CompilePSP(string.Format(fileNameTmp, "update"));
                }
                if (cbCreateDelete.Checked)
                {
                    if (result != "") result += "\r\n\r\n";
                    result += CompilePSP(string.Format(fileNameTmp, "delete"));
                }

                this.Invoke(new Function(delegate()
                {
                    txtCompileResult.Text = result;
                }));

            }
        }

        private void cbCreateAutoCompile_CheckedChanged(object sender, EventArgs e)
        {
            if( cbCreateAutoCompile.Checked ) cbCreateToFiles.Checked = true;
        }

        private void bwCompile_DoWork(object sender, DoWorkEventArgs e)
        {
            this.StartCompile();
        }

        private void bwCompile_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

            btnGenerate.Text = "Generate";
            btnGenerate.Enabled = true;
           
        }

        private void cbCreateToFiles_CheckedChanged(object sender, EventArgs e)
        {
            if (!cbCreateToFiles.Checked) cbCreateAutoCompile.Checked = false;

        }

        private void btnCompile_Click(object sender, EventArgs e)
        {
            string fileName = lblResultFilename.Text;
            if (fileName.Trim() == "") return;
            txtCompileResult.Text = "Compiling...";
            tabControl1.SelectTab(3);
            txtCompileResult.Select(0, 0);
           
            System.Threading.Thread.Sleep(5);
            if (!System.IO.Directory.Exists(this.GetFileDestination)) System.IO.Directory.CreateDirectory(this.GetFileDestination);

            System.IO.File.WriteAllText(fileName, tb.Text);
            System.Threading.Thread.Sleep(500);

            txtCompileResult.Text = CompilePSP(fileName);

        }

        private void btnResultLoadFiles_Click(object sender, EventArgs e)
        {
            cbResultFiles.Items.Clear();
            string[] fileEntries = Directory.GetFiles(this.GetFileDestination);
            foreach (string fileName in fileEntries)
                cbResultFiles.Items.Add(Path.GetFileName(fileName));
        }

        private void cbResultFiles_SelectedIndexChanged(object sender, EventArgs e)
        {
            lblResultFilename.Text = this.GetFileDestination + cbResultFiles.Text;
            tb.Text = File.ReadAllText(lblResultFilename.Text);
        }

        private void btnResultSave_Click(object sender, EventArgs e)
        {
            if (lblResultFilename.Text.Trim() == "") return;
            var btn = (Button)sender;
            var title = btn.Text;
            btn.Text = "Saving...";
            btn.Enabled = false;
            System.IO.File.WriteAllText(lblResultFilename.Text, tb.Text);
            System.Threading.Thread.Sleep(300);
            System.Media.SystemSounds.Beep.Play();
            btn.Enabled = true;
            btn.Text = title;

        }

        private void tb_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.S)       // Ctrl-S Save
            {
                btnResultSave_Click(btnResultSave, new EventArgs());
                e.SuppressKeyPress = true; 
            }
            if (e.KeyCode == Keys.F5)      
            {
                btnCompile_Click(btnCompile, new EventArgs());
                e.SuppressKeyPress = true;  
            }


        }

        private void btnResultOpenFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFD = new OpenFileDialog();
            openFD.Filter = "psp files (*.psp)|*.psp|sql files (*.sql)|*.sql";
            openFD.FilterIndex = 1;
            openFD.RestoreDirectory = true;

            if (openFD.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    lblResultFilename.Text = openFD.FileName;
                    tb.Text = File.ReadAllText(lblResultFilename.Text);                            
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
                }
            }
        }

        private void btnSync_Click(object sender, EventArgs e)
        {
            new Synchronizer().Show();
        }

        private void btnSnippetCreate_Click(object sender, EventArgs e)
        {
            if (cbListTableNames.Text == "")
            {
                MessageBox.Show("Please select a table in List Tab");
                return;
            }

            pspTmp.CreateSnippet(cbSnippetCodeType,cbListTableNames.Text, clListProcParams, txtSnippetResult);
        }

        private void btnSnippetCopy_Click(object sender, EventArgs e)
        {
            Clipboard.SetDataObject(txtSnippetResult.Text, true);
        }

    }
}
